package com.ushine.web.component.authority.aop;

import com.ushine.web.base.facade.IUserRedisFacade;
import com.ushine.web.base.model.base.DataFilterMetaDataBO;
import com.ushine.web.base.model.system.DataPermissionDO;
import com.ushine.web.base.model.system.UserDO;
import com.ushine.web.component.authority.DataFilterTypeEnum;
import com.ushine.web.component.authority.annotation.DataPermissionFilter;
import com.ushine.web.component.authority.config.DataFilterThreadLocal;
import com.ushine.web.component.exception.LoginErrorEnum;
import com.ushine.web.component.exception.ServiceException;
import com.ushine.web.component.utils.EnumBaseUtils;
import com.ushine.web.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yls
 * @Date 2022/2/17 15:48
 * @Description: 数据权限切面类
 * @Version 1.0
 **/
@Aspect
@Component
@Slf4j
public class AuthorityAspect {

    @Resource
    private IUserRedisFacade userRedisFacade;

    @Pointcut("@annotation(com.ushine.web.component.authority.annotation.DataPermissionFilter)")
    public void authorityPointcut() {
        // 定义切点
    }

    /**
     * 功能描述:
     * 〈环绕通知：可以监控方法从开始到结束的执行情况〉
     *
     * @param joinPoint 切入流程
     * @return : void
     * @author : yls
     * @date : 2020/10/20 10:16
     */
    @Around("authorityPointcut()")
    public Object authorityAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        String methodName = method.getName();
        // 获取类名
        Object target = joinPoint.getTarget();
        Class<?> aClass = target.getClass();
        String className = aClass.getName();

        log.info("**************{}***{}***本次数据权限-start*********************************************", className, methodName);
        // 组装环境类
        DataFilterMetaDataBO dataFilterMetaDataBO = new DataFilterMetaDataBO();
        // 获取当前用户名
        UserDO user = SecurityUtils.getUser();
        log.info("当前登录用户：{}", user);
        if (user == null) {
            user = DataFilterThreadLocal.getUser();
            // 如果线程传递的用户信息和系统当前用户信息均为null
            if (user == null) {
                throw new ServiceException(LoginErrorEnum.USER_NOT_LOGIN);
            }
            log.info("当前登录用户组装的权限信息：{}", dataFilterMetaDataBO);
        } else {
            DataFilterThreadLocal.clear();
            dataFilterMetaDataBO.setUserId(user.getId());
        }
        /*
         * 通过当前登录的用户id获取对应操作的数据权限
         */
        // 获取当前方法的注解
        DataPermissionFilter dataPermissionFilter = method.getAnnotation(DataPermissionFilter.class);
        // 根据功能获取对应的数据隔离权限
        String function = dataPermissionFilter.function();
        // 获取缓存中的用户权限
        String username = user.getUsername();
        DataPermissionDO userDataPermission = userRedisFacade.getUserDataPermission(username, function);
        // 获取数据级别：枚举类
        DataPermissionDO finalUserDataPermission = userDataPermission;
        Optional<DataFilterTypeEnum> dataFilterTypeEnum = EnumBaseUtils.getEnumObject(DataFilterTypeEnum.class, obj -> obj.getType() == finalUserDataPermission.getFilterType());
        if (dataFilterTypeEnum.isPresent()) {
            dataFilterMetaDataBO.setFilterType(dataFilterTypeEnum.get());
        } else {
            dataFilterMetaDataBO.setFilterType(DataFilterTypeEnum.SELF_CREATE);
        }
        dataFilterMetaDataBO.setUserId(user.getId());
        dataFilterMetaDataBO.setDeptId(userDataPermission.getOrgId());
        // 多个部门id
        String orgIds = userDataPermission.getOrgIds();
        if (StringUtils.isNotBlank(orgIds)) {
            String[] split = orgIds.split(",");
            List<String> depIdList = Arrays.asList(split);
            Set<Long> deptIds = depIdList.stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toSet());
            dataFilterMetaDataBO.setDeptIds(deptIds);
        } else {
            Set<Long> deptIds = new HashSet<>();
            deptIds.add(-1L);
            dataFilterMetaDataBO.setDeptIds(deptIds);
        }
        dataFilterMetaDataBO.setDataPermission(userDataPermission);
        /*
         * 获取用户的权限：测试
         */
        //testByDev(joinPoint, dataFilterMetaDataBO);

        // 注入权限
        DataFilterThreadLocal.setDataFilter(dataFilterMetaDataBO);
        Object proceed = joinPoint.proceed();
        DataFilterThreadLocal.clear();
        log.info("**************{}***{}***本次数据权限-end*********************************************", className, methodName);
        return proceed;
    }

}
